/**
    \file tp6.cpp

    \brief Programme de manipulation de forme.

    \author   Clement Zotti 11074801
    \author   Ousmane Iria 10100204
    \date     12/04/2012
    \version  v1.0

    <b>Entrees:</b>
        \li (\c clavier) Lecture d'action (\c chaine de caractères)
        \li (\c clavier) Lecture du type de figure (\c entier)
        \li (\c fichier) Lecture des coordonnées (\c entier)

    <b>Sorties:</b>
        \li (\c écran) Affiche les figures dans le canevas (\c chaine de caractères)
        \li (\c écran) Affiche les vecteurs des figures (\c chaine de caractères)

    Ce programme aide le pilote pour le choix d'un aéroport, selon
    la méthode de tri choisie. Dans un premier temps, le pilote
    entre ses coordonnées GPS dans le programme. Ensuite il choisie une action
    entre ("alpha.", "distance.", "suivant.", "fin."), en fonction de ce choix
    soit le programme tri en fonction des coordonnées, soit en fonction des
    distance le séparant des aéroports. Ou il peut a nouveau rentrer ses
    nouvelles coordonnées et enfin il peut aussi mettre fin au programme.

    Date de la premiere version: 22/03/2012 \n

    Date de modification:
        \li 22/03/2012, modification des fonctions et ajout des commentaires, Clement Zotti
*/

#include <string>
#include <vector>
#include <iostream>
#include "canevas.h"
#include "point.h"
#include "ligne.h"
#include "rectangle.h"
#include "triangle.h"
#include "cercle.h"

// Déclaration des constantes
const double PI = 3.141592654;

const int VAL_CERCLE = 1;
const int VAL_RECTANGLE = 2;
const int VAL_TRIANGLE = 3;


const int VAL_AJOUT = 11;
const int VAL_EFFAC = 13;
const int VAL_LISTER = 12;
const int VAL_ROTAT = 14;
const int VAL_DEPLAC = 15;
const int VAL_TAILLE = 16;
const int VAL_FIN = -10;

/**
  \brief Fonction pricipale du programme du traitement d'image.

  Cette fonction manipule les images contenus dans la liste

  Cette fonction est correcte.
  Cette fonction n'est pas robuste.
**/
int main()
{
	// Déclaration des fonctions
	void Manipulation_Forme(void);

	//Boucle principale
	Manipulation_Forme();
	return 0;
}


/**
  \brief Fonction pricipale du programme du traitement d'image.

  Cette fonction manipule les images contenus dans la liste

  Cette fonction est correcte.
  Cette fonction n'est pas robuste.

  \param[in,out] list_rect, vecteur de rectangle
  \param[in,out] list_cercle, vecteur de cercle
  \param[in,out] list_triangle, vecteur de triangle
**/
void Manipulation_Forme(void)
{
	// Déclaration des fonctions
	void Ajouter_figure(vector<Rectangle> &, vector<Cercle> &, vector<Triangle> &);
	void Retirer_figure(vector<Rectangle> &, vector<Cercle> &, vector<Triangle> &);
	void Afficher_figure(vector<Rectangle> &, vector<Cercle> &, vector<Triangle> &, Canevas&, bool);
	void Rotation_figure(vector<Rectangle> &, vector<Cercle> &, vector<Triangle> &);
	void Deplacer_figure(vector<Rectangle> &, vector<Cercle> &, vector<Triangle> &);
	void Taille_figure(vector<Rectangle> &, vector<Cercle> &, vector<Triangle> &);
	int lecture_action();

	// Déclaration des variables
	Canevas myCan;
	vector<Rectangle> liste_rectangle;
	vector<Cercle> liste_cercle;
	vector<Triangle> liste_triangle;

	int action = -1;

	// Boucle principale
	while(action != VAL_FIN)
	{
		cout << "Entrez l'action souhaite, ajouter(a), lister(l), effacer(e), rotation(r)," <<
				" deplacement(d), taille(t), fin(f)";
		action = lecture_action();
		switch(action)
		{
			case VAL_AJOUT :
				Ajouter_figure(
						liste_rectangle,
						liste_cercle,
						liste_triangle);
				break;
			case VAL_LISTER :
				Afficher_figure(
						liste_rectangle,
						liste_cercle,
						liste_triangle,
						myCan,
						true);
				break;
			case VAL_EFFAC :
				Afficher_figure(
						liste_rectangle,
						liste_cercle,
						liste_triangle,
						myCan,
						true);

				Retirer_figure(
						liste_rectangle,
						liste_cercle,
						liste_triangle);

				myCan.effacer();

				Afficher_figure(
						liste_rectangle,
						liste_cercle,
						liste_triangle,
						myCan,
						false);
				break;
			case VAL_ROTAT :
				Afficher_figure(
						liste_rectangle,
						liste_cercle,
						liste_triangle,
						myCan,
						true);

				Rotation_figure(
						liste_rectangle,
						liste_cercle,
						liste_triangle);

				myCan.effacer();

				Afficher_figure(
						liste_rectangle,
						liste_cercle,
						liste_triangle,
						myCan,
						false);
				break;
			case VAL_DEPLAC :
				Afficher_figure(
						liste_rectangle,
						liste_cercle,
						liste_triangle,
						myCan,
						true);

				Deplacer_figure(
						liste_rectangle,
						liste_cercle,
						liste_triangle);

				myCan.effacer();

				Afficher_figure(
						liste_rectangle,
						liste_cercle,
						liste_triangle,
						myCan,
						false);
				break;
			case VAL_TAILLE :
				Afficher_figure(
						liste_rectangle,
						liste_cercle,
						liste_triangle,
						myCan,
						true);

				Taille_figure(
						liste_rectangle,
						liste_cercle,
						liste_triangle);

				myCan.effacer();

				Afficher_figure(
						liste_rectangle,
						liste_cercle,
						liste_triangle,
						myCan,
						false);
				break;
			default:
				break;
		}
	}
}

/**
  \brief Fonction ajouter figure.

  Cette fonction ajoute une figure a un vecteur qui correspond
  a la figure.

  Cette fonction est correcte.
  Cette fonction n'est pas robuste.

  \param[in,out] list_rect, vecteur de rectangle
  \param[in,out] list_cercle, vecteur de cercle
  \param[in,out] list_triangle, vecteur de triangle
 **/
void Ajouter_figure(vector<Rectangle> &list_rect,
					vector<Cercle> &list_cercle,
					vector<Triangle> &list_triangle)
{
	// Déclaration des fonctions
	int lecture_action();

	// Déclaration des variables
	Cercle cercle_tmp;
	Point centre;
	int rayon;

	Rectangle rect_tmp;
	Point p_gauche, p_droit;

	Triangle tri_tmp;
	Point p_1, p_2,p_3;

	int action;

	int x1,y1;
	int x2,y2;
	int x3,y3;

	// Boucle principale
	cout << "Entrez le type de figure cercle(1), rectangle(2), triangle(3) :" << endl;
	cin >> action;

	switch(action)
	{
		case VAL_CERCLE :
			cout << "Entrez le centre du vercle (x y): ";
			cin >> x1 >> y1;
			cout << "Entrez le rayon du chercle (entier): ";
			cin >> rayon;
			p_1.init(x1,y1);
			cercle_tmp.init(rayon, p_1);
			list_cercle.push_back(cercle_tmp);
			break;
		case VAL_RECTANGLE :
			cout << "Entrez le point haut gauche du rectangle (x y): ";
			cin >> x1 >> y1;
			cout << "Entrez le point bas droit du rectangle (x y): ";
			cin >> x2 >> y2;
			p_gauche.init(x1,y1);
			p_droit.init(x2,y2);
			rect_tmp.init(p_gauche, p_droit);
			list_rect.push_back(rect_tmp);
			break;
		case VAL_TRIANGLE :
			cout << "Entrez le point 1 du triangle: ";
			cin >> x1 >> y1;
			cout << "Entrez le point 2 du triangle: ";
			cin >> x2 >> y2;
			cout << "Entrez le point 3 du triangle: ";
			cin >> x3 >> y3;

			p_1.init(x1, y1);
			p_2.init(x2, y2);
			p_3.init(x3, y3);

			tri_tmp.init(p_1, p_2, p_3);

			list_triangle.push_back(tri_tmp);
			break;
	}
}


/**
  \brief Fonction retirer figure

  Cette fonction retire une figure d'un des vecteurs de figure.

  Cette fonction est correcte.
  Cette fonction n'est pas robuste.

  \param[in,out] list_rect, vecteur de rectangle
  \param[in,out] list_cercle, vecteur de cercle
  \param[in,out] list_triangle, vecteur de triangle
 **/
void Retirer_figure(vector<Rectangle> &list_rect,
					vector<Cercle> &list_cercle,
					vector<Triangle> &list_triangle)
{
	// Déclaration des variables
	int action, index;

	// Boucle principale

	cout << "Entrez le type de figure cercle(1), rectangle(2), triangle(3) :" << endl;
	cin >> action;

	cout << "Entrez l'index de la figure à enlever : ";
	cin >> index;

	switch(action)
	{
		case VAL_RECTANGLE :
			if(list_rect.size() > 0)
				list_rect.erase(list_rect.begin() + index);
			break;
		case VAL_CERCLE :
			if(list_cercle.size() > 0)
				list_cercle.erase(list_cercle.begin() + index);
			break;
		case VAL_TRIANGLE :
			if(list_triangle.size() > 0)
				list_triangle.erase(list_triangle.begin() + index);
			break;
	}
}


/**
  \brief Fonction affichage des figures.

  Cette fonction affiche toutes les images présentes dans les
  vecteurs de figure.

  Cette fonction est correcte.
  Cette fonction n'est pas robuste.

  \param[in,out] list_rect, vecteur de rectangle
  \param[in,out] list_cercle, vecteur de cercle
  \param[in,out] list_triangle, vecteur de triangle
  \param[in]	 affiche_info, booleen pour afficher les informations
 **/
void Afficher_figure(vector<Rectangle> &list_rect,
					vector<Cercle> &list_cercle,
					vector<Triangle> &list_triangle,
					Canevas & cv,
					bool affiche_info)
{
	// Déclaration des fonctions
	void Afficher_canevas_figure(Rectangle, Canevas &);
	void Afficher_canevas_figure(Cercle, Canevas &);
	void Afficher_canevas_figure(Triangle, Canevas &);

	// Déclaration des variables
	Point p1,p2,p3;
	int rayon;

	// Boucle principale

	for(int i = 0 ; i < (int)list_cercle.size() ; i++)
	{
		if(affiche_info)
		{
			cout << "FORME : CERCLE " << endl;
			p1 = list_cercle.at(i).val_Centre();
			rayon = list_cercle.at(i).val_Rayon();
			cout << "Forme #" << i << endl;
			cout << "Point centre : " <<
					p1.valX() << " " << p1.valY() << endl;
			cout << "Rayon : " <<
					rayon << endl;
		}
		Afficher_canevas_figure(list_cercle.at(i), cv);
	}

	for(int i = 0 ; i < (int)list_rect.size() ; i++)
	{

		if(affiche_info)
		{
			cout << "FORME : RECTANGLE " << endl;
			p1 = list_rect.at(i).val_P_Gauche();
			p2 = list_rect.at(i).val_P_Droit();

			cout << "Forme #" << i << endl;
			cout << "Point Gauche : " <<
					p1.valX() << " " << p1.valY() << endl;
			cout << " Point Droit : " <<
					p2.valX() << " " << p2.valY() << endl;
		}
		Afficher_canevas_figure(list_rect.at(i), cv);

	}

	for(int i = 0 ; i < (int)list_triangle.size() ; i++)
	{
		if(affiche_info)
		{
			cout << "FORME : TRIANGLE " << endl;
			p1 = list_triangle.at(i).val_P1();
			p2 = list_triangle.at(i).val_P2();
			p3 = list_triangle.at(i).val_P3();
			cout << "Forme #" << i << endl;
			cout << "Point 1 : " <<
					p1.valX() << " " << p1.valY() << endl;
			cout << "Point 2 : " <<
					p2.valX() << " " << p2.valY() << endl;
			cout << "Point 3 : " <<
					p3.valX() << " " << p3.valY() << endl;
		}
		Afficher_canevas_figure(list_triangle.at(i), cv);
	}
}

/**
  \brief Fonction affichage d'une figure.

  Cette fonction affiche une rectangle sur le caneva

  Cette fonction est correcte.
  Cette fonction n'est pas robuste.

  \param[in] r, rectangle
  \param[in,out] cv
**/
void Afficher_canevas_figure(Rectangle r, Canevas &cv)
{
	r.afficher(cv);
}

/**
  \brief Fonction affichage d'une figure.

  Cette fonction affiche une cercle sur le caneva

  Cette fonction est correcte.
  Cette fonction n'est pas robuste.

  \param[in] c, cercle
  \param[in,out] cv
**/
void Afficher_canevas_figure(Cercle c, Canevas &cv)
{
	c.afficher(cv);
}

/**
    \brief Fonction affichage d'une figure.

  Cette fonction affiche une triangle sur le caneva

  Cette fonction est correcte.
  Cette fonction n'est pas robuste.

  \param[in] t, triangle
  \param[in,out] cv
**/
void Afficher_canevas_figure(Triangle t, Canevas &cv)
{
	t.afficher(cv);
}

/**
  \brief Fonction rotation figure.

  Cette fonction effectue une rotation sur une figure d'un vecteur

  Cette fonction est correcte.
  Cette fonction n'est pas robuste.

  \param[in,out] list_rect, vecteur de rectangle
  \param[in,out] list_cercle, vecteur de cercle
  \param[in,out] list_triangle, vecteur de triangle
 **/
void Rotation_figure(vector<Rectangle> &list_rect,
					vector<Cercle> &list_cercle,
					vector<Triangle> &list_triangle)
{
	// Déclaration des variables
	int action, index;
	double angle;
	Point centre;
	int x, y;

	// Boucle principale
	cout << "Entrez le type de figure rectangle(2), triangle(3) :" << endl;
	cin >> action;

	cout << "Entrez l'index de la figure :" << endl;
	cin >> index;

	cout << "Entrez le point central de rotation : " << endl;
	cin >> x >> y;
	centre.init(x, y);

	cout << " Entrez l'angle de rotation (degree) : " << endl;
	cin >> angle;

	switch(action)
	{
		case VAL_RECTANGLE :
			list_rect.at(index).rotation(centre, angle * PI / 180.0);
			break;
		case VAL_TRIANGLE :
			list_triangle.at(index).rotation(centre, angle * PI / 180.0);
			break;
	}
}

/**
  \brief Fonction Deplacer figure.

  Cette fonction deplace une figure d'un des vecteurs.

  Cette fonction est correcte.
  Cette fonction n'est pas robuste.

  \param[in,out] list_rect, vecteur de rectangle
  \param[in,out] list_cercle, vecteur de cercle
  \param[in,out] list_triangle, vecteur de triangle
 **/
void Deplacer_figure(vector<Rectangle> &list_rect,
					vector<Cercle> &list_cercle,
					vector<Triangle> &list_triangle)
{
	// Déclaration des variables
	int action, index;
	int x, y;

	// Boucle principale
	cout << "Entrez le type de figure cercle(1), rectangle(2), triangle(3) :" << endl;
	cin >> action;

	cout << "Entrez l'index de la figure :" << endl;
	cin >> index;

	cout << "Entrez le deplacement en x et y : " << endl;
	cin >> x >> y;

	switch(action)
	{
		case VAL_CERCLE :
			list_cercle.at(index).deplacement(x,y);
			break;
		case VAL_RECTANGLE :
			list_rect.at(index).deplacement(x,y);
			break;
		case VAL_TRIANGLE :
			list_triangle.at(index).deplacement(x,y);
			break;
	}
}


/**
  \brief Fonction Taille figure.

  Cette fonction modifie la taille d'une figure présente dans un
  vecteur, avec une proportion et un point ancrage.

  Cette fonction est correcte.
  Cette fonction n'est pas robuste.

  \param[in,out] list_rect, vecteur de rectangle
  \param[in,out] list_cercle, vecteur de cercle
  \param[in,out] list_triangle, vecteur de triangle
 **/
void Taille_figure(vector<Rectangle> &list_rect,
		vector<Cercle> &list_cercle,
		vector<Triangle> &list_triangle)
{
	// Déclaration des variables
	int action, index;
	float proportion;
	Point ancre;
	int x, y;

	// Boucle principale
	cout << "Entrez le type de figure cercle(1), rectangle(2), triangle(3) :" << endl;
	cin >> action;

	cout << "Entrez l'index de la figure :" << endl;
	cin >> index;

	cout << "Entrez le point central de proportion : " << endl;
	cin >> x >> y;
	ancre.init(x, y);

	cout << " Entrez la proportion : " << endl;
	cin >> proportion;

	switch(action)
	{
		case VAL_CERCLE :
			list_cercle.at(index).deplacementProp(ancre, proportion);
			break;
		case VAL_RECTANGLE :
			list_rect.at(index).modif_taille(ancre, proportion);
			break;
		case VAL_TRIANGLE :
			list_triangle.at(index).modif_taille(ancre, proportion);
			break;
	}
}

/**
 \brief Lecture d'une action au clavier

 Cette fonction lit une action au clavier jusqu'à qu'elle soit bonne.

 Cette fonction est correcte.
 Cette fonction est robuste.

  \return Valeur de l'action choisie
 **/
int lecture_action()
{
	// Déclaration des constantes
	const string AJOUT = "a";
	const string EFFAC = "e";
	const string LISTER = "l";
	const string ROTAT = "r";
	const string DEPLAC = "d";
	const string TAILLE = "t";
	const string FIN = "f";

	// Declaration des variables locales
	string action = "";
	int val = -1;

	// Corps de la fonction
	do
	{
		cin >> action;
		if (action == AJOUT)
		{
			val = VAL_AJOUT;
		}
		else if (action == EFFAC)
		{
			val = VAL_EFFAC;
		}
		else if (action == LISTER)
		{
			val = VAL_LISTER;
		}
		else if (action == ROTAT)
		{
			val = VAL_ROTAT;
		}
		else if (action == DEPLAC)
		{
			val = VAL_DEPLAC;
		}
		else if (action == TAILLE)
		{
			val = VAL_TAILLE;
		}
		else if (action == FIN)
		{
			val = VAL_FIN;
		}
	} while (val == -1);

	return val;
	// ne pas oublier le retour
}


